#ifndef CODE_LINE_H
#define CODE_LINE_H

#include <vector>
#include <string>

#include "PositionInfo.h"
#include "GOAL.h"

namespace GOAL
{


  class Code_Line;

  /**
   * @class Code_Line_Iterator
   * @brief an iterator that traverses a Code_Line
   * @see   Code_Line 
   */

  class Code_Line_Iterator
  {
  public:  
    // = Necessary traits
    typedef std::bidirectional_iterator_tag iterator_category;
    typedef Code_Line value_type;
    typedef Code_Line * pointer;
    typedef Code_Line & reference;
    typedef int difference_type;

    /// constructor
    Code_Line_Iterator(Code_Line & code_line, bool end = false);

    /// copy constructor
    Code_Line_Iterator(const Code_Line_Iterator& iterator);

    /// destructor
    ~Code_Line_Iterator();

    /// Dereference operator returns a reference to the item contained
    /// at the current position
    virtual MgaObject& operator* (void);

    /// Returns a const reference to the item contained at the current position
    virtual const MgaObject& operator* (void) const;

    /// Preincrement operator
    virtual Code_Line_Iterator &operator++ (void);

    /// Postincrement operator
    Code_Line_Iterator operator++ (int);

    /// Minus operator (needed for std::sort because of its optimizations).
    int operator- (const Code_Line_Iterator& rhs);

    /// Minus operator (needed for std::sort because of its optimizations).
    int operator- (int decrement);

    /// Plus operator (needed for std::sort because of its optimizations).
    Code_Line_Iterator operator+ (int increment);

    /// Plus operator (needed for std::sort because of its optimizations).
    Code_Line_Iterator operator+ (int increment) const;

    Code_Line_Iterator& operator= (const Code_Line_Iterator& rhs);

    /// Equality operator
    virtual bool operator== (const Code_Line_Iterator &rhs) const;

    /// Nonequality operator
    virtual bool operator!= (const Code_Line_Iterator &rhs) const;

  private:
    Code_Line & code_line_;
    unsigned int pos_;
  };

  /**
   * @class Code_Line_Iterator
   * @brief an iterator that traverses a Code_Line
   * @see   Code_Line 
   */

  class Code_Line
  {
  public:
    friend class Code_Line_Iterator;
    friend class Code_Lines;
    typedef Code_Line_Iterator iterator;
    typedef const Code_Line_Iterator const_iterator;


    /// constructor and destructor
    Code_Line();
    Code_Line(const std::vector <GOAL::MgaObject> & source);
    Code_Line(const Code_Line & source);
    ~Code_Line();

    /// insert an object into the code line
    /// @param object the object to insert into the Code_Line
    void insert (const MgaObject& object);

    /// return the number of MgaObjects in the Code_Line
    unsigned int size (void);

    /// return the MgaObjects in string form by type
    std::string output (void);

    /// helper function for comparing two MgaObjects (checks x position)
    static bool lessThan(const GOAL::MgaObject& a, const GOAL::MgaObject& b);

    /// One code line is less than another if it has a smaller y position
    bool operator< (const Code_Line& rhs) const;

    Udm::Object parent ();

    /// get iterator to first element
    iterator begin ();

    /// get iterator to first element
    const_iterator begin () const;

    /// get iterator to element past the last element
    iterator end ();
      
    /// get iterator to element past the last element
    const_iterator end () const;

    // Returns a reference to the <index> element in the Code_Line without
    // checking for range errors.
    const GOAL::MgaObject &operator[] (size_t index) const;

    /// get a sorted copy of this Code Line (by x position)
    Code_Line getSorted ();

    /// checks to see if the code line already has the object
    bool exists (const MgaObject& object);

    /// position information for top left of this code line
    GME::Position::Pair position;
  private:
    std::vector <MgaObject> objects_;
    std::map <MgaObject,unsigned int> object_lookups_;
  };

}


#endif
